using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;

using ViewOnCore.Helper.WPF;
using ViewOnCore.HostContract.Media;
using ViewOnCore.HostContract;
using ViewOnCore.Helper.Security;

#region Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.

/*
 Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.
 This work is copyrighted in its entirety. Permission to use "ViewOn.tv"
 material may be granted only after we receive a written request from you,
 and you receive written permission from us.

 While ViewOn Media Services provides the information herein to anyone,
 we retain copyright on all code, text, graphic images, and other content.
 This means that you may not distribute the code, the text or graphics to others without the
 express written permission of ViewOn Media Services; "mirror" this information on your server
 without our permission; or modify or reuse the code, text or graphics on our servers.
 You may print copies of the information for your own personal use; and, you may reference
 the Service from your own documents. Any commercial use of this material is prohibited without
 the written permission of ViewOn Media Services. In all copies of this information, you must
 retain this notice and any other copyright notices originally included with such information.

 This material may be protected by U.S. and International Copyright laws, and you are legally
 bound by the copyright notices on those systems.

 "ViewOn" logos and other official symbols or graphics may not be used in connection with any
 product or service that has not been expressly authorized in advance in writing or in any manner
 that is likely to cause confusion among the users of this or other Web sites or among the public.
 All other seals, graphics or trademarks of organizations not affiliated with ViewOn Media Services
 that appear on this site are the property of their respective owners.

 ViewOn Media Services reserve all other rights. 
*/

#endregion

#region ViewOn.tv Source Code Licence

/*
This license governs use of the ViewOn.tv software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Summary

The source code is made available to view for reference purposes or to contribute to the project only. Developers may not distribute or modify the code for commercial or non-commercial purposes without express Agreement of View On Media Services.

2. Definitions

The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
"Licensor" means the company "ViewOn Media Services".
"You" means the licensee of the software, who is not engaged in designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software.
"Your company" means the company you worked for when you downloaded the software.
"Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes of debugging and maintaining your products. For clarity, "reference use" does NOT include (a) the right to use the software for purposes of designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software, and (b) the right to distribute the software outside of your company.
"Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor under this license.

3. Grant of Rights

(A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free copyright license to reproduce the software for reference use.
(B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free patent license under licensed patents for reference use.
4. Limitations
(A) No Trademark License- This license does not grant you any rights to use the Licensor's name, logo, or trademarks.
(B) If you begin patent litigation against the Licensor over patents that you think may apply to the software (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
(C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
 */

#endregion

namespace ViewOnCore.Helper.WPF
{

    public delegate void ChildWindowDialogClosedHandler(ChildWindowDecorator childWindow);

    public enum ChildWindowDecoratorState
    {
        Opened,
        Closed,
        DesktopIcon
    }

    /// <summary>
    /// A decorator is used to create a "child window" in ViewOn.tv.
    /// 
    /// Theses windows are :
    /// - are childs windows by default
    /// - can be converted to 'ViewOn.tv Desktop Icons'
    /// - can be detached
    /// </summary>
    public partial class ChildWindowDecorator : ContentControl
    {

        #region Variables

        //---- Xml Database
        static internal XmlDocument _xmlDatabase;
        static private XmlEncrypter _xmlEncrypter = Host.CreateEncrypter();
        static private string _dbFileName = "wd.vod";

        //----
        private Desktop _desktop;
        private string _key;
        public MediaData _mediaData;
        private XmlNode _node;

        private ChildWindowDialogClosedHandler _childWindowDialogClosedHandler;

        //---- Properties
        static private DependencyProperty HasCloseButtonProperty;
        static private DependencyProperty HasMiniModeButtonProperty;
        static private DependencyProperty HasTopBarProperty;
        static private DependencyProperty IsModalProperty;
        static private DependencyProperty IsResizableProperty;
        static public DependencyProperty MoveWindowFromBarProperty;
        static private DependencyProperty IsAnimatedProperty;

        //---- Generic properties
        private Dictionary<string, string> _genericProperties = new Dictionary<string, string>();

        //---- Animation
        private Storyboard _hideChildWindowStoryboard;

        //----
        public ChildWindowDecoratorState WindowState = ChildWindowDecoratorState.Opened;
        public WindowStartupLocation StartupPosition = WindowStartupLocation.CenterOwner;

        //---- Events

        /// <summary>
        /// Notifiy that the control is ready.
        /// </summary>
        public event EventHandler VisuallyReady;

        /// <summary>
        /// Activate the mini mode
        /// </summary>
        public event EventHandler MiniModeActivated;

        /// <summary>
        /// Occurs when the window as about to close.
        /// </summary>
        public event EventHandler Closed;

        /// <summary>
        //  Occurs directly after System.Windows.Window.Close() is called, and can be
        //  handled to cancel window closure.
        /// </summary>
        public event CancelEventHandler Closing;

        //---- Allow attacheable / detacheable windows
        private ChildDetachableWindow _detachableWindow;

        //----
        public DesktopIcon DesktopIcon;

        //---- Background
        private Rectangle _background;

        #endregion

        #region Constructor

        static ChildWindowDecorator()
        {
            // Used to define the default style of this control.
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ChildWindowDecorator), new FrameworkPropertyMetadata(typeof(ChildWindowDecorator)));

            // Properties
            HasMiniModeButtonProperty = DependencyProperty.Register("HasMiniMode",
                                                                typeof(bool),
                                                                typeof(ChildWindowDecorator),
                                                                new FrameworkPropertyMetadata(false));

            HasCloseButtonProperty = DependencyProperty.Register("HasCloseButton",
                                                                typeof(bool),
                                                                typeof(ChildWindowDecorator),
                                                                new FrameworkPropertyMetadata(true));

            HasTopBarProperty = DependencyProperty.Register("HasTopBar",
                                                            typeof(bool),
                                                            typeof(ChildWindowDecorator),
                                                            new FrameworkPropertyMetadata(true));

            IsModalProperty = DependencyProperty.Register("IsModal",
                                                            typeof(bool),
                                                            typeof(ChildWindowDecorator),
                                                            new FrameworkPropertyMetadata(false));

            IsResizableProperty = DependencyProperty.Register("IsResizable",
                                                                typeof(bool),
                                                                typeof(ChildWindowDecorator),
                                                                new FrameworkPropertyMetadata(true));

            MoveWindowFromBarProperty = DependencyProperty.Register("MoveWindowFromBar",
                                                                typeof(bool),
                                                                typeof(ChildWindowDecorator),
                                                                new FrameworkPropertyMetadata(true));

            IsAnimatedProperty = DependencyProperty.Register("IsAnimated",
                                                    typeof(bool),
                                                    typeof(ChildWindowDecorator),
                                                    new FrameworkPropertyMetadata(true));
        }

        public ChildWindowDecorator()
        {
            DesktopIcon = new DesktopIcon(this);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            //---- Handle events
            ((Border)SearchFrameworkElement("root")).MouseLeftButtonDown += new MouseButtonEventHandler(root_PreviewMouseLeftButtonDown);

            //---- Background;
            _background = SearchFrameworkElement("background") as Rectangle;

            //---- Top bar
            Border headerBar = SearchFrameworkElement("headerBar") as Border;
            Border headerBarBackground = SearchFrameworkElement("headerBarBackground") as Border;
            if (!HasTopBar)
            {
                headerBar.Visibility = Visibility.Collapsed;
                headerBarBackground.Visibility = Visibility.Collapsed;

                Grid rootGrid = SearchFrameworkElement("rootGrid") as Grid;
                rootGrid.RowDefinitions[0].Height = new GridLength(0);
            }

            //---- Has close button
            if (HasCloseButton)
            {
                ((Button)SearchFrameworkElement("btnClose")).Click += new RoutedEventHandler(this.btnClose_Click);
                ((Button)SearchFrameworkElement("btnClose")).Visibility = Visibility.Visible;
            }

            //---- Has mini mode button
            if (HasMiniModeButton)
            {
                ((Button)SearchFrameworkElement("btnMiniMode")).Click += new RoutedEventHandler(this.btnMiniMode_Click);
                ((Button)SearchFrameworkElement("btnMiniMode")).Visibility = Visibility.Visible;
            }

            //---- Show as a desktop icon
            if (WindowState == ChildWindowDecoratorState.DesktopIcon)
            {
                ((FrameworkElement)Parent).Opacity = 0;
                IsAnimated = false;
            }

            //---- Is animated
            if (!IsAnimated)
            {
                // Display it directly
                Visibility = Visibility.Visible;
                Opacity = 1;
                Grid grid = (Grid)SearchFrameworkElement("griMain");
                grid.RenderTransform = null;
            }
            else
            {
                //---- Set opacity to 0
                Opacity = 0;
            }

            //---- IsResizable
            if (!IsResizable)
            {
                Grid grip = SearchFrameworkElement("grip") as Grid;
                grip.Visibility = Visibility.Hidden;

                ContentPresenter content = SearchFrameworkElement("Content") as ContentPresenter;
                content.Margin = new Thickness();
            }
            else
            {
                ((Border)SearchFrameworkElement("rectSizeSouthEast")).MouseDown += new MouseButtonEventHandler(OnSizeSouthEast);
            }

            this.Loaded += new RoutedEventHandler(ChildWindowDecorator_Loaded);
        }

        void ChildWindowDecorator_Loaded(object sender, RoutedEventArgs e)
        {
            if (IsAnimated)
            {
                //---- Animation
                Storyboard show = FindResource("ShowChildWindow") as Storyboard;
                show = show.Clone();

                show.Completed += new EventHandler(show_Completed);
                show.Begin(this, this.Template);
            }
            else
            {
                //---- Display it directly
                show_Completed(null, null);
            }
        }

        void show_Completed(object sender, EventArgs e)
        {
            ((Button)SearchFrameworkElement("btnClose")).IsEnabled = true;

            if (VisuallyReady != null)
                VisuallyReady(this, null);

            //---- Show this library as a icon ?
            if (WindowState == ChildWindowDecoratorState.DesktopIcon)
            {
                ((UserControl)Parent).Visibility = Visibility.Collapsed;
                ((UserControl)Parent).Opacity = 1;
                SetAsDesktopIcon();
            }
        }

        #endregion

        #region Event : Mouse down on window

        void root_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (_detachableWindow != null)
                return;

            if (MoveWindowFromBar)
                if (Mouse.GetPosition(this).Y > ((Border)SearchFrameworkElement("headerBar")).ActualHeight)
                    return;

            if (!_isResizing)
                _desktop.OnStartMoveChildWindow(this, e);
        }

        #endregion

        #region Event : close button

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            CancelEventArgs args = new CancelEventArgs();

            if (Closing != null)
                Closing(this, args);

            if (!args.Cancel)
                this.Close();

            if (Closed != null)
                Closed(this, null);
        }

        #endregion

        #region Event : Mini mode button

        private void btnMiniMode_Click(object sender, RoutedEventArgs e)
        {
            if (MiniModeActivated != null)
                MiniModeActivated(this, null);
        }

        #endregion

        #region Properties

        /// <summary>
        /// The associated desktop
        /// </summary>
        public Desktop Desktop
        {
            get { return _desktop; }
        }

        /// <summary>
        /// The window key.
        /// </summary>
        public string Key
        {
            get
            {
                return _key;
            }
            set
            {
                // Force to completely recreate the node
                //if (_desktop != null)
                //    RemoveXml();

                _key = value;
                if (_desktop != null)
                    UpdateXml();
            }
        }

        /// <summary>
        /// Gives access to the detacheable window
        /// </summary>
        public ChildDetachableWindow DetachableWindow
        {
            get
            {
                return _detachableWindow;
            }
            set
            {
                _detachableWindow = value;
            }
        }

        /// <summary>
        /// Can we move the window when draging its top bar.
        /// </summary>
        public bool MoveWindowFromBar
        {
            get
            {
                return (bool)base.GetValue(MoveWindowFromBarProperty);
            }
            set
            {
                base.SetValue(MoveWindowFromBarProperty, value);
            }
        }

        /// <summary>
        /// An associated default media data
        /// </summary>
        public MediaData MediaData
        {
            get
            {
                return _mediaData;
            }
            set
            {
                _mediaData = value;

                //---- Title update
                if (_mediaData != null)
                    _mediaData.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(DesktopIcon.mediaData_PropertyChanged);
            }
        }

        /// <summary>
        /// Used to change the background's brush.
        /// </summary>
        public Brush BackgroundBrush
        {
            set
            {
                _background.Fill = value;
            }
        }

        /// <summary>
        /// Used to change the background's stroke.
        /// </summary>
        public Brush BackgroundStroke
        {
            set
            {
                _background.Stroke = value;
            }
        }

        /// <summary>
        /// Give access to some generic properties associated with the window.
        /// </summary>
        public Dictionary<string, string> GenericProperties
        {
            get
            {
                return _genericProperties;
            }
        }

        #endregion

        #region Properties : Has/Is...

        /// <summary>
        /// Does this window is animated or not.
        /// </summary>
        public bool IsAnimated
        {
            get
            {
                return (bool)base.GetValue(IsAnimatedProperty);
            }
            set
            {
                base.SetValue(IsAnimatedProperty, value);
            }
        }

        /// <summary>
        /// Display the "close" button or not
        /// </summary>
        public bool HasTopBar
        {
            get
            {
                return (bool)GetValue(HasTopBarProperty);
            }
            set
            {
                SetValue(HasTopBarProperty, value);
            }
        }

        /// <summary>
        /// Display the "mini mode" button or not
        /// </summary>
        public bool HasMiniModeButton
        {
            get
            {
                return (bool)GetValue(HasMiniModeButtonProperty);
            }
            set
            {
                SetValue(HasMiniModeButtonProperty, value);
            }
        }

        /// <summary>
        /// Display the "close" button or not
        /// </summary>
        public bool HasCloseButton
        {
            get
            {
                return (bool)GetValue(HasCloseButtonProperty);
            }
            set
            {
                SetValue(HasCloseButtonProperty, value);
            }
        }

        /// <summary>
        /// Is the window modal or not
        /// </summary>
        public bool IsModal
        {
            get
            {
                return (bool)GetValue(IsModalProperty);
            }
            set
            {
                SetValue(IsModalProperty, value);
            }
        }

        /// <summary>
        /// Is the window resizable or not
        /// </summary>
        public bool IsResizable
        {
            get
            {
                return (bool)GetValue(IsResizableProperty);
            }
            set
            {
                SetValue(IsResizableProperty, value);
            }
        }

        #endregion

        #region Show

        /// <summary>
        /// Show the window in no modal mode.
        /// </summary>
        /// <param name="container">The desktop</param>
        public void Show(Desktop container)
        {
            _desktop = container;

            //---- Check the position to insure it is visible
            _desktop.InsureVisible(this);

            _desktop.AddChildWindow(this, false);
        }

        #endregion

        #region ShowDialog

        /// <summary>
        /// Show the window but as modal.
        /// </summary>
        /// <param name="container">The desktop.</param>
        public void ShowDialog(Desktop container)
        {
            _desktop = container;
            _desktop.AddChildWindow(this, true);

            UpdateXml();
        }

        /// <summary>
        /// Show the window as modal. Once closed it call the handler method.
        /// </summary>
        public void ShowDialog(Desktop container, ChildWindowDialogClosedHandler handler)
        {
            _desktop = container;
            _childWindowDialogClosedHandler = handler;
            _desktop.AddChildWindow(this, true);

            UpdateXml();
        }

        #endregion

        #region BringToTop

        /// <summary>
        /// Bring the window to the top position.
        /// </summary>
        public void BringToTop()
        {
            _desktop.BringToTop((UserControl)this.Parent);
        }

        #endregion

        #region Close

        /// <summary>
        /// Close the window.
        /// </summary>
        public void Close()
        {
            WindowState = ChildWindowDecoratorState.Closed;

            if (_detachableWindow != null)
            {
                _detachableWindow.OnClose();
            }
            else
            {
                Grid griMain = (Grid)SearchFrameworkElement("griMain");
                //_showChildWindowStoryboard = (Storyboard)griMain.FindResource("ShowChildWindow");
                _hideChildWindowStoryboard = (Storyboard)griMain.FindResource("HideChildWindow");

                Storyboard storyboard = _hideChildWindowStoryboard.Clone();
                storyboard.Completed += new EventHandler(storyboard_Completed);
                storyboard.Begin(this);
            }

            //---- Update state
            if (!(Parent is DesktopIcon))
                RemoveXml();
        }

        void storyboard_Completed(object sender, EventArgs e)
        {
            _desktop.RemoveChildWindow(this);

            if (_childWindowDialogClosedHandler != null)
                _childWindowDialogClosedHandler(this);
        }

        #endregion

        #region Helpers

        public Window GetOwnerWindow()
        {
            FrameworkElement element = this.Parent as FrameworkElement;
            while (element.Parent != null)
                element = element.Parent as FrameworkElement;

            return element as Window;
        }

        private FrameworkElement FindParentName(FrameworkElement current, string name)
        {
            if (current.Name == name)
                return current;

            if (current.Parent == null)
                return null;

            return FindParentName(current.Parent as FrameworkElement, name);
        }

        public object SearchFrameworkElement(string name)
        {
            object obj = Template.FindName(name, this);
            if (obj != null)
                return obj;
            return FindName(name);
        }

        #endregion

        #region Grip - Sizing event handlers

        void OnSizeSouthEast(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (_detachableWindow != null)
                return;

            _sizingAction = SizingAction.SouthEast;
            OnStartResize();
        }

        Point _resizeOrigin;
        double _originalWidth;
        double _originalHeight;
        SizingAction _sizingAction;
        bool _isResizing = false;

        private void OnStartResize()
        {
            _isResizing = true;

            _resizeOrigin = Mouse.GetPosition(_desktop.ChildWindowsCanvas);
            _originalWidth = ((UserControl)this.Parent).ActualWidth;
            _originalHeight = ((UserControl)this.Parent).ActualHeight;

            _desktop.ChildWindowsCanvas.MouseLeftButtonUp += new MouseButtonEventHandler(childWindowsCanvas_MouseLeftButtonUp);
            _desktop.ChildWindowsCanvas.MouseMove += new MouseEventHandler(childWindowsCanvas_MouseMove);
            _desktop.OnStartResizingChildWindow();
        }

        void childWindowsCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_detachableWindow != null)
                return;

            _isResizing = false;
            _desktop.OnEndResizingChildWindow();

            _desktop.ChildWindowsCanvas.MouseLeftButtonUp -= new MouseButtonEventHandler(childWindowsCanvas_MouseLeftButtonUp);
            _desktop.ChildWindowsCanvas.MouseMove -= new MouseEventHandler(childWindowsCanvas_MouseMove);

            //---- Update state
            UpdateXml();
        }

        void childWindowsCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (_detachableWindow != null)
                return;

            Point point = Mouse.GetPosition(_desktop.ChildWindowsCanvas);
            double widthDelta = 0;
            double heightDelta = 0;

            switch (_sizingAction)
            {
                case SizingAction.NorthEast:
                    widthDelta = point.X - _resizeOrigin.X;
                    heightDelta = _resizeOrigin.Y - point.Y;
                    break;
                case SizingAction.NorthWest:
                    widthDelta = _resizeOrigin.X - point.X;
                    heightDelta = _resizeOrigin.Y - point.Y;
                    break;
                case SizingAction.SouthEast:
                    widthDelta = point.X - _resizeOrigin.X;
                    heightDelta = point.Y - _resizeOrigin.Y;
                    break;
                case SizingAction.SouthWest:
                    widthDelta = _resizeOrigin.X - point.X;
                    heightDelta = point.Y - _resizeOrigin.Y;
                    break;
            }

            // Update the width and height, making sure we don't set to below zero
            ((UserControl)this.Parent).Width = Math.Max(0, _originalWidth + widthDelta);
            ((UserControl)this.Parent).Height = Math.Max(0, _originalHeight + heightDelta);
        }

        #endregion

        #region Attach / Detach

        /// <summary>
        /// Detach the window.
        /// </summary>
        public void Detach()
        {
            _desktop.Detach(this);
        }

        /// <summary>
        /// Attach the window.
        /// </summary>
        public void Attach()
        {
            _desktop.Attach(this);
        }

        #endregion

        #region SetAsDesktopIcon

        /// <summary>
        /// Convert the window into a 'Desktop Icon'
        /// </summary>
        public void SetAsDesktopIcon()
        {
            //---- Update state
            WindowState = ChildWindowDecoratorState.DesktopIcon;

            //---- Keep the same position (Will also save the new state).
            if (Double.IsNaN(Canvas.GetLeft(DesktopIcon)) && Double.IsNaN(Canvas.GetTop(DesktopIcon)))
                _desktop.MoveDesktopIcon(DesktopIcon, new Point(Canvas.GetLeft((UIElement)this.Parent), Canvas.GetTop((UIElement)this.Parent)));

            _desktop.AddDesktopIcon(DesktopIcon);

            //---- Hide this window
            ((UserControl)this.Parent).Visibility = Visibility.Collapsed;

            //---- Update the Xml
            UpdateXml();
        }

        #endregion

        #region Save/Load state

        static private void InitializeDatabase()
        {
            if (_xmlDatabase != null)
                return;

            //---- Load
            _xmlDatabase = _xmlEncrypter.LoadEncryptedXML(Host.SettingsService.CachePath + _dbFileName);

            //---- Create the empty Db
            if (_xmlDatabase == null)
            {
                _xmlDatabase = new XmlDocument();
                _xmlDatabase.LoadXml("<db></db>");
                _xmlEncrypter.SaveEncryptedXML(_xmlDatabase, Host.SettingsService.CachePath + _dbFileName);
                return;
            }
        }

        internal void RemoveXml()
        {
            if (_key == null)
                return;

            if (_node != null)
                _node.ParentNode.RemoveChild(_node);

            _node = null;

            _xmlEncrypter.SaveEncryptedXML(_xmlDatabase, Host.SettingsService.CachePath + _dbFileName);
        }

        public void UpdateXml()
        {
            if (_key == null)
                return;

            InitializeDatabase();

            if (Dispatcher.CheckAccess())
            {
                AsyncUpdateXml();
                return;
            }

            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
                (DelegateInvoker)delegate()
                {
                    AsyncUpdateXml();
                });
        }

        private void AsyncUpdateXml()
        {
            string position = "";
            string positionIcon = "";
            FrameworkElement parent = (FrameworkElement)Parent;

            // Positions
            position = ((int)Canvas.GetLeft((FrameworkElement)Parent)) + ";" + ((int)Canvas.GetTop((FrameworkElement)Parent));
            positionIcon = ((int)Canvas.GetLeft(DesktopIcon)) + ";" + ((int)Canvas.GetTop(DesktopIcon));

            // When not visible (Show as desktop icon)
            string size = ((int)parent.ActualWidth) + ";" + ((int)parent.ActualHeight);
            if (parent.ActualWidth == 0 && parent.ActualHeight == 0)
                size = ((int)parent.Width) + ";" + ((int)parent.Height);

            if (_node == null)
                _node = _xmlDatabase.SelectSingleNode("/db/Child[@Key='" + XmlConvert.EncodeLocalName(_key) + "']");

            XmlAttribute attribute;
            if (_node == null)
            {
                //---- Create the node
                _node = _xmlDatabase.CreateElement("Child");
                XmlNode rootNode = _xmlDatabase.SelectSingleNode("/db");
                rootNode.AppendChild(_node);

                attribute = _xmlDatabase.CreateAttribute("Key");
                attribute.Value = XmlConvert.EncodeLocalName(_key);
                _node.Attributes.Append(attribute);

                attribute = _xmlDatabase.CreateAttribute("DesktopKey");
                attribute.Value = XmlConvert.EncodeLocalName(_desktop.Key);
                _node.Attributes.Append(attribute);

                attribute = _xmlDatabase.CreateAttribute("State");
                attribute.Value = XmlConvert.EncodeLocalName(this.WindowState.ToString());
                _node.Attributes.Append(attribute);

                attribute = _xmlDatabase.CreateAttribute("Position");
                attribute.Value = XmlConvert.EncodeLocalName(position);
                _node.Attributes.Append(attribute);

                attribute = _xmlDatabase.CreateAttribute("PositionIcon");
                attribute.Value = XmlConvert.EncodeLocalName(positionIcon);
                _node.Attributes.Append(attribute);

                attribute = _xmlDatabase.CreateAttribute("Size");
                attribute.Value = XmlConvert.EncodeLocalName(size);
                _node.Attributes.Append(attribute);
            }
            else
            {
                //---- Update
                _node.Attributes["Key"].Value = XmlConvert.EncodeLocalName(_key);
                _node.Attributes["DesktopKey"].Value = XmlConvert.EncodeLocalName(_desktop.Key);
                _node.Attributes["State"].Value = XmlConvert.EncodeLocalName(this.WindowState.ToString());

                _node.Attributes["Position"].Value = XmlConvert.EncodeLocalName(position);
                _node.Attributes["PositionIcon"].Value = XmlConvert.EncodeLocalName(positionIcon);

                if (WindowState != ChildWindowDecoratorState.DesktopIcon)
                    _node.Attributes["Size"].Value = XmlConvert.EncodeLocalName(size);
            }

            //---- Generic properties
            foreach (string key in _genericProperties.Keys)
            {
                if (_node.Attributes[key] == null)
                {
                    attribute = _xmlDatabase.CreateAttribute(key);
                    attribute.Value = XmlConvert.EncodeLocalName(_genericProperties[key]);
                    _node.Attributes.Append(attribute);
                }
                else
                    _node.Attributes[key].Value = XmlConvert.EncodeLocalName(_genericProperties[key]);
            }

            _xmlEncrypter.SaveEncryptedXML(_xmlDatabase, Host.SettingsService.CachePath + _dbFileName);
        }

        static public XmlNodeList FindXml(string desktopKey)
        {
            InitializeDatabase();

            return _xmlDatabase.SelectNodes("/db/Child[@DesktopKey='" + XmlConvert.EncodeLocalName(desktopKey) + "']");
        }

        public void LoadXml()
        {
            if (_key == null)
                return;

            InitializeDatabase();

            _node = _xmlDatabase.SelectSingleNode("/db/Child[@Key='" + XmlConvert.EncodeLocalName(_key) + "']");

            //---- Generic properties
            _genericProperties.Clear();
            foreach (XmlAttribute attribute in _node.Attributes)
                if (attribute.Name != "Key" &&
                    attribute.Name != "DesktopKey" &&
                    attribute.Name != "State" &&
                    attribute.Name != "Position" &&
                    attribute.Name != "PositionIcon" &&
                    attribute.Name != "Size")
                    _genericProperties[attribute.Name] = XmlConvert.DecodeName(attribute.Value);

            //---- Other properties
            string childManagerKey = XmlConvert.DecodeName(_node.Attributes["DesktopKey"].Value);

            string state = XmlConvert.DecodeName(_node.Attributes["State"].Value);
            WindowState = (ChildWindowDecoratorState)Enum.Parse(typeof(ChildWindowDecoratorState), state);

            string position = XmlConvert.DecodeName(_node.Attributes["Position"].Value);
            string[] xy = position.Split(';');
            Canvas.SetLeft((FrameworkElement)this.Parent, Int32.Parse(xy[0]));
            Canvas.SetTop((FrameworkElement)this.Parent, Int32.Parse(xy[1]));

            try
            {
                string positionIcon = XmlConvert.DecodeName(_node.Attributes["PositionIcon"].Value);
                xy = positionIcon.Split(';');
                Canvas.SetLeft(DesktopIcon, Int32.Parse(xy[0]));
                Canvas.SetTop(DesktopIcon, Int32.Parse(xy[1]));
            }
            catch
            {
                // Compatibility : use the same position as window
                Canvas.SetLeft(DesktopIcon, Int32.Parse(xy[0]));
                Canvas.SetTop(DesktopIcon, Int32.Parse(xy[1]));
            }

            string size = XmlConvert.DecodeName(_node.Attributes["Size"].Value);
            string[] wh = size.Split(';');
            ((FrameworkElement)this.Parent).Width = Int32.Parse(wh[0]);
            ((FrameworkElement)this.Parent).Height = Int32.Parse(wh[1]);
        }

        #endregion

    }
}